package com.addcn.addcnwebview.webview;

import android.Manifest;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.net.http.SslError;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.util.AttributeSet;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.SslErrorHandler;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.AbsoluteLayout;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;

import com.addcn.addcnwebview.BuildConfig;
import com.addcn.addcnwebview.CustomChromeCallback;
import com.addcn.addcnwebview.OnChooserListener;
import com.addcn.addcnwebview.R;
import com.addcn.addcnwebview.WebFullscreenHolder;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import ren.yale.android.cachewebviewlib.WebViewCacheInterceptorInst;
import ren.yale.android.cachewebviewlib.utils.NetUtils;

/**
 * author:luwenbo
 * created on date : 2019-12-06
 * content:
 * describe:
 */
public class CustomWebview extends WVJBWebView {
    private Context mContext;
    private final static String[] mChooser = new String[]{"拍照", "相簿"};
    private ValueCallback<Uri> mUploadMessage;
    private ValueCallback<Uri[]> mUploadMessageLollipop;
    private CustomWebViewClient customWebViewClient;
    private CustomWebChromeClient webChromeClient;
    private WebSettings webSettings;
    private ProgressBar progressbar;
    private boolean isScroll = true;
    private boolean showPro = true;
    private CustomWebview.onOveredScroll overedScroll;
    private long startTime = 0;
    private Drawable progressDrawable = null;
    private boolean networkImage = false;
    protected FrameLayout.LayoutParams COVER_SCREEN_PARAMS = new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
    WebFullscreenHolder fullscreenContainer;
    private OnChooserListener onChooserListener;
    private Dialog mChooserDialog;
    private WebViewDataHelper dataHelper;
    private CustomChromeCallback customChromeCallback;
    private CustomConfig customConfig;
    public CustomWebview(Context context, AttributeSet attrs) {
        super(getFixedContext(context), attrs);
        mContext = context;
        initWeb(context,attrs);
    }

    private void initWeb(Context context, AttributeSet attrs) {
        if (Build.VERSION.SDK_INT >=23){
            if (attrs != null){
                TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CustomX5Webview);
                progressDrawable = array.getDrawable(R.styleable.CustomX5Webview_pro_drawable);
                showPro = array.getBoolean(R.styleable.CustomX5Webview_pro_show,true);
                isScroll = array.getBoolean(R.styleable.CustomX5Webview_pro_scroll,true);
            }else{
                progressDrawable = ContextCompat.getDrawable(context, R.drawable.webview_progressbar);
            }
            progressbar = new ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal);
            progressbar.setLayoutParams(new AbsoluteLayout.LayoutParams(AbsoluteLayout.LayoutParams.MATCH_PARENT, 5, 0, 0));
            progressbar.setProgressDrawable(progressDrawable);
            if (showPro) {
                addView(progressbar);
            }
        }
        mContext = context;
        dataHelper = new WebViewDataHelper();
        initDialog(context);
    }

    public CustomWebview(Context context) {
        super(getFixedContext(context));
        mContext = context;
        initWeb(context,null);
    }

    public static Context getFixedContext(Context context) {
        if (Build.VERSION.SDK_INT >= 21 && Build.VERSION.SDK_INT < 23) {
            // Avoid crashing on Android 5 and 6 (API level 21 to 23)
            return context.createConfigurationContext(new Configuration());
        }
        return context;
    }

    public void setOveredScroll(CustomWebview.onOveredScroll overedScroll) {
        this.overedScroll = overedScroll;
    }

    public void setNetworkImage(boolean networkImage) {
        this.networkImage = networkImage;
    }

    public boolean isShowPro() {
        return showPro;
    }

    public void setShowPro(boolean showPro) {
        showPro = showPro;
    }

    public ValueCallback<Uri> getmUploadMessage() {
        return mUploadMessage;
    }

    public boolean isScroll() {
        return isScroll;
    }

    public void setScroll(boolean scroll) {
        isScroll = scroll;
    }

    public void setmUploadMessage(ValueCallback<Uri> mUploadMessage) {
        this.mUploadMessage = mUploadMessage;
    }

    public ValueCallback<Uri[]> getmUploadMessageLollipop() {
        return mUploadMessageLollipop;
    }

    public void setmUploadMessageLollipop(ValueCallback<Uri[]> mUploadMessageLollipop) {
        this.mUploadMessageLollipop = mUploadMessageLollipop;
    }

    public void setOnChooserListener(OnChooserListener onChooserListener) {
        this.onChooserListener = onChooserListener;
    }

    public void setCustomChromeCallback(CustomChromeCallback customChromeCallback) {
        this.customChromeCallback = customChromeCallback;
    }

    @Override
    protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
        super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
        if (overedScroll != null) {
            overedScroll.onOvered(scrollY);
        }
    }

    public <T, R> void addRegister(final String handleName, WVJBWebView.WVJBHandler<T, R> handler) {
        registerHandler(handleName, handler);
    }

    public WebViewClient mWebViewClient = new WebViewClient(){

        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (customConfig.getCustomWebViewClient() != null){
                cusShouldOverrideUrlLoading(view,url);
                return true;
            }
            return super.shouldOverrideUrlLoading(view, url);
        }

        @Nullable
        @Override
        public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
            //if (BuildConfig.DEBUG){
            if (customConfig != null && customConfig.isWebContentsDebuggingEnabled()){
                return super.shouldInterceptRequest(view, url);
            }
            return  WebViewCacheInterceptorInst.getInstance().interceptRequest(url);
        }

        @Override
        public WebResourceResponse shouldInterceptRequest(WebView webView, WebResourceRequest webResourceRequest) {
           // if (BuildConfig.DEBUG){
            if (customConfig != null && customConfig.isWebContentsDebuggingEnabled()){
                return super.shouldInterceptRequest(webView, webResourceRequest);
            }
            return  WebViewCacheInterceptorInst.getInstance().interceptRequest( webResourceRequest);
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (networkImage){
                setNetworkImage(false);
            }
            Log.d(this.getClass().getName(),"==onPageFinished");
            loadUrl("javascript:App.resize(document.body.getBoundingClientRect().height)");
            loadUrl("javascript:var objs=document.querySelectorAll('.lazy-loading');var img=new Array();for(var i=0;i<objs.length;i++){var obj={};obj.src=objs[i].src;obj.alt=objs[i].alt;img.push(obj)}for(var i=0;i<objs.length;i++){objs[i].onclick=function(){console.log(img);var obj=img[0];var src=this.src;var link=(this.parentElement.tagName=='A').toString();setupWebViewJavascriptBridge(function(bridge){bridge.callHandler('openPhotos',{'image':src,'images':img,'hasLink':link,},function responseCallback(responseData){responseCallback(data)})})}}");
        }
        @Override
        public void onReceivedSslError(WebView webView, SslErrorHandler sslErrorHandler, SslError sslError) {
            if (BuildConfig.DEBUG){
                sslErrorHandler.proceed();
            }else{
                super.onReceivedSslError(webView, sslErrorHandler, sslError);
            }
        }
    };

    private void cusShouldOverrideUrlLoading(WebView view, String url) {

    }


    /**
     * 預設設定
     */
    public void initWebView(CustomConfig customConfig) {
        if (customConfig == null){
            return;
        }
        if (customConfig.getCustomWebViewClient()== null){
            customWebViewClient = new CustomWebViewClient(){
                @Override
                public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
                    return super.shouldOverrideUrlLoading(view, request);
                }

                @Nullable
                @Override
                public WebResourceResponse shouldInterceptRequest(WebView view, String url) {
                    return super.shouldInterceptRequest(view, url);
                }
            };
        }else{
            customWebViewClient = customConfig.getCustomWebViewClient();
        }
        customWebViewClient.setNetworkImage(networkImage);
        setWebViewClient(customWebViewClient);
        if (networkImage){
            setNetworkImage(true);
        }
        if (webChromeClient == null || customConfig.getWebChromeClient() == null){
            initDialog(mContext);
            webChromeClient = new CustomWebChromeClient(){
                @Override
                public void onShowCustomView(View view, WebChromeClient.CustomViewCallback callback) {
                    super.onShowCustomView(view, callback);
                    if (customChromeCallback != null){
                        customChromeCallback.onShowCustomView(view);
                    }
                    postDelayed(() -> openFullscreen(view)
                            , 200);
                }

                @Override
                public void onHideCustomView() {
                    super.onHideCustomView();
                    FrameLayout decor = (FrameLayout) ((Activity) mContext).getWindow().getDecorView();
                    decor.removeView(fullscreenContainer);
                    setVisibility(VISIBLE);
                    fullscreenContainer = null;
                    if (customChromeCallback != null){
                        customChromeCallback.onHideCustomView();
                    }
                }

                //這個是WebVeiw的隱藏方法
                public void openFileChooser(ValueCallback<Uri> uploadMsg) {
                    mUploadMessage = uploadMsg;
                    if (mChooserDialog != null) {
                        mChooserDialog.show();
                    }
                }


                public void openFileChooser(ValueCallback<Uri> uploadMsg,
                                            String acceptType) {
                    openFileChooser(uploadMsg);
                }


                public void openFileChooser(ValueCallback<Uri> uploadMsg,
                                            String acceptType, String capture) {
                    openFileChooser(uploadMsg);
                }

                @Override
                public boolean onShowFileChooser(WebView webView, ValueCallback<Uri[]> filePathCallback, FileChooserParams fileChooserParams) {
                    mUploadMessageLollipop = filePathCallback;
                    if (mChooserDialog != null){
                        mChooserDialog.show();
                    }
                    return true;
                    //return super.onShowFileChooser(webView, filePathCallback, fileChooserParams);
                }
            };
        }else{
            webChromeClient = customConfig.getWebChromeClient();
        }
        webChromeClient.setProgressBar(progressbar);
        setWebChromeClient(webChromeClient);
        //預設縮放50%
        setInitialScale(50);
        webSettings = this.getSettings();
        if (networkImage) {
            webSettings.setBlockNetworkImage(true);//圖片後載入
        }
        webSettings.setJavaScriptEnabled(true);
        webSettings.setDefaultTextEncodingName("UTF-8");// 設定在解碼時使用的預設編碼
        webSettings.setAllowFileAccess(true);// 是否可以訪問檔案
        webSettings.setUseWideViewPort(true);
        if (NetUtils.isConnected(mContext)) {
            webSettings.setCacheMode(WebSettings.LOAD_DEFAULT);
        } else {
            webSettings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
        }

        if (Build.VERSION.SDK_INT < 21) {
            android.webkit.CookieSyncManager.createInstance(mContext.getApplicationContext());

        }
        //自適應螢幕、快取設定
        webSettings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
        webSettings.setLoadWithOverviewMode(true);
        webSettings.setDomStorageEnabled(true);
        webSettings.setDatabaseEnabled(true);
        webSettings.setAppCacheEnabled(true);
        webSettings.setGeolocationEnabled(true);
        webSettings.setBuiltInZoomControls(true);
        webSettings.setSupportZoom(false);
        webSettings.setDisplayZoomControls(false);
        webSettings.setJavaScriptCanOpenWindowsAutomatically(true);
        String path = mContext.getDir("cache", Context.MODE_PRIVATE).getPath();
        webSettings.setGeolocationDatabasePath(path);
        webSettings.setAppCachePath(path);
        webSettings.setAppCacheEnabled(false);//APP快取
        webSettings.setAppCacheMaxSize(customConfig.getMaxCacheSize());
        webSettings.setDefaultFontSize(18);
        webSettings.setMediaPlaybackRequiresUserGesture(true);
        if (customConfig.isWebContentsDebuggingEnabled()) {
            setWebContentsDebuggingEnabled(true);
        }else{
            if (BuildConfig.DEBUG){
                setWebContentsDebuggingEnabled(true);
            }
        }
        webSettings.setAllowUniversalAccessFromFileURLs(true);
        requestFocus();
        //去除滾動條
        setHorizontalScrollBarEnabled(false);
        setVerticalScrollBarEnabled(false);
        // listview,webview中滾動拖動到頂部或者底部時的陰影
        setOverScrollMode(View.OVER_SCROLL_NEVER);
    }



    private void initDialog(Context mContext) {
        mChooserDialog = new AlertDialog.Builder(mContext)
                .setItems(mChooser, (dialog, which) -> {
                    switch (which) {
                        case 0:
                            if (lacksPermissions(Manifest.permission.CAMERA)) {
                                if (onChooserListener != null){
                                    onChooserListener.openPermissions();
                                }
                            } else {
                                Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
                                if (takePictureIntent.resolveActivity(mContext.getPackageManager()) != null) {
                                    File photoFile = null;
                                    try {
                                        photoFile = createImageFile();
                                    } catch (IOException exception) {
                                        exception.printStackTrace();
                                    }
                                    if (photoFile != null) {
                                        Uri photoUri = FileProvider.getUriForFile(mContext,mContext.getPackageName()+".fileprovider",photoFile);
                                        takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);
                                        if (onChooserListener != null){
                                            onChooserListener.chooserPhoto(takePictureIntent,photoUri);
                                        }
                                    }
                                }
                            }
                            break;
                        case 1:
                                Intent pickPhoto = new Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
                            if (onChooserListener != null){
                                onChooserListener.chooserPhoto(pickPhoto,null);
                            }
                            break;
                        default:
                            break;
                    }
                }).create();
        mChooserDialog.setCanceledOnTouchOutside(false);
        mChooserDialog.setOnKeyListener((dialog, keyCode, event) -> {
            if (keyCode == KeyEvent.KEYCODE_BACK && mUploadMessage != null) {
                mChooserDialog.dismiss();
                mUploadMessage.onReceiveValue(null);
                return true;
            }
            return false;
        });

    }

    private File createImageFile() throws IOException{
        String timeStamp=new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.TAIWAN).format(new Date());
        String imageFileName="JPEG_"+timeStamp+"_";
        File storageDir= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
        if(!storageDir.exists()){
            storageDir.mkdirs();
        }
        return File.createTempFile(imageFileName,".jpg",storageDir);
    }

    // 判斷許可權集合
    public boolean lacksPermissions(String... permissions) {
        for (String permission : permissions) {
            if (lacksPermission(permission)) {
                return true;
            }
        }
        return false;
    }

    // 判斷是否缺少許可權
    private boolean lacksPermission(String permission) {
        return ContextCompat.checkSelfPermission(mContext, permission) ==
                PackageManager.PERMISSION_DENIED;
    }

    public void openFullscreen(View view) {
        FrameLayout decor = (FrameLayout) ((Activity) mContext).getWindow().getDecorView();
        fullscreenContainer = new WebFullscreenHolder(mContext);
        fullscreenContainer.addView(view, COVER_SCREEN_PARAMS);
        decor.addView(fullscreenContainer, COVER_SCREEN_PARAMS);
    }

    public WebSettings getSetting() {
        if (webSettings == null) {
            return getSetting();
        }
        return webSettings;
    }

    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        if (progressbar != null){
            AbsoluteLayout.LayoutParams lp = (AbsoluteLayout.LayoutParams) progressbar.getLayoutParams();
            lp.x = l;
            lp.y = t;
            progressbar.setLayoutParams(lp);
        }
        super.onScrollChanged(l, t, oldl, oldt);
    }


    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
    }


    @Override
    public void scrollTo(int x, int y) {
        if (isScroll) {
            super.scrollTo(0, 0);
        } else {
            super.scrollTo(x, y);
        }
    }
    public interface OnWebLoadListener {
        void onStart(WebView webView, String url);

        void onLoadResource(String url);

        void onFinish(WebView webView, String url);
    }

    public interface onOveredScroll {
        void onOvered(int scrollY);
    }


}
